<?php

/**
 * Interface for Loader class.
 *
 * @package nuclide
 * @author Mats Lundberg
 */
interface nuc_Loader_Interface
{
	public function loadClass($className);
	public function loadFunctions($functionsName);
	public function classLoadable($className);
	public function setRootDirectory($directory);
}

/**
 * Static version of above interface.
 * 
 * PHP does not allow to overwrite non-static function with static versions.
 *
 * @package nuclide
 * @author Mats Lundberg
 */
interface nuc_Loader_Static_Interface
{
	public static function loadClass($className);
	public static function loadFunctions($functionsName);
	public static function classLoadable($className);
	public static function setRootDirectory($directory);
}

/**
 * Abstract version of Loader. Function classToFilename should be defined.
 *
 * 
 * 
 * @package nuclide
 * @author Mats Lundberg
 */
abstract class nuc_Loader_Abstract implements nuc_Loader_Interface 
{
	/**
	 * Array of root directories to search in.
	 *
	 * @var array
	 */
	protected $rootDirectories = array('.');
	
	public function __construct($rootDirectory)
	{
		$this->setRootDirectory($rootDirectory);
	}
	
	/**
	 * Load php-file with class.
	 *
	 * @param string $className
	 */
	public function loadClass($className)
	{
		$this->loadFile($this->classToFilename($className));
	}
	
	/**
	 * Load file o' function.
	 *
	 * @param unknown_type $functionsName
	 */
	public function loadFunctions($functionsName)
	{
		$this->loadFile($this->functionsToFilename($functionsName));
	}
	
	/**
	 * Load a file from root directories.
	 *
	 * @param string $file
	 */
	protected function loadFile($file)
	{
		foreach($this->rootDirectories as $root)
		{
			if(file_exists($root.$file))
			{
				require_once($root.$file);
				return;
			}
		}
		
		throw new nuc_Loader_AbstractException('Failed to load '.$file.' from '. implode(',', $this->rootDirectories));
	}
	
	/**
	 * Find out if class is loadable, ie. exists where it should according to the rules.
	 *
	 * @param string $className
	 */
	public function classLoadable($className)
	{
		$path = $this->classToFilename($className);

		foreach ($this->rootDirectories as $root)
		{
			if(file_exists($root.$path) && is_readable($root.$path))
				return true;
		}
		
		return false;
	}

	/**
	 * Set root directory
	 *
	 * @param string $className
	 */
	public function setRootDirectory($directory)
	{
		if(!is_string($directory))
			return;
				
		$this->rootDirectories = array($directory);
	}
	
	/**
	 * Add a root directory
	 *
	 * @param unknown_type $directory
	 */
	public function addRootDirectory($directory)
	{
		if(!is_string($directory))
			throw new nuc_Loader_AbstractException('Given directory is not a string.');
		
		#if(!in_array($directory, $this->rootDirectories))
		array_push($this->rootDirectories, $directory);
	}
	
	/**
	 * Convert className to filename. Subclass would decide how to convert the name.
	 *
	 * @param string $className
	 */
	abstract protected function classToFilename($className);
	
	/**
	 * Convert functions name to filename. Subclass would decide how to convert the name.
	 *
	 * @param string $functionsName
	 */
	abstract protected function functionsToFilename($functionsName);
}

class nuc_Loader_AbstractException extends Exception
{
}

?>